package com.gitee.wsl.ext.reflect

import kotlin.plus
import kotlin.reflect.KClass
import kotlin.reflect.KClassifier
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection

actual fun KType.withNullability(nullable: Boolean): KType {
    if (nullable == isMarkedNullable) return this
    return KTypeImpl1(classifier!!, arguments, nullable)
}

class KTypeImpl1(
    override val classifier: KClassifier,
    override val arguments: List<KTypeProjection>,
    override val isMarkedNullable: Boolean
) : KType {
    override fun equals(other: Any?): Boolean =
        other is KTypeImpl &&
                classifier == other.classifier && arguments == other.arguments && isMarkedNullable == other.isMarkedNullable

    override fun hashCode(): Int =
        (classifier.hashCode() * 31 + arguments.hashCode()) * 31 + isMarkedNullable.hashCode()

    override fun toString(): String {
        val kClass = (classifier as? KClass<*>)
        val classifierName = when {
            kClass == null -> classifier.toString()
            kClass.simpleName != null -> kClass.simpleName
            else -> "(non-denotable type)"
        }

        val args =
            if (arguments.isEmpty()) ""
            else arguments.joinToString(", ", "<", ">")
        val nullable = if (isMarkedNullable) "?" else ""

        return classifierName + args + nullable
    }
}


 actual class KTypeImpl
actual constructor(
    actual override val classifier: KClassifier?,
    actual override val arguments: List<KTypeProjection>,
    actual override val isMarkedNullable: Boolean,
    actual override val annotations: List<Annotation>,
) : KType, EitherNetKType {
    private val impl = EitherNetKTypeImpl(classifier, arguments, isMarkedNullable, annotations)

    override fun equals(other: Any?) = impl == other

    override fun hashCode() = impl.hashCode()

    override fun toString() = impl.toString()
}
